package com.productivity.util;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Point2D;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Scanner;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileFilter;

import com.productivity.model.common.Vertex3D;

public class AnimationCreator extends Canvas implements Serializable,MouseListener,MouseMotionListener,KeyListener {
	private static final long serialVersionUID = -4270735017984238742L;


	public static void main(String[] args) {
		JFileChooser fileChooser = new JFileChooser();
		JFrame frame = new JFrame();
		int picked = JOptionPane.showConfirmDialog(null,
                "Would you like to open a file?", "",
                JOptionPane.YES_NO_OPTION);
		if(picked==JOptionPane.YES_OPTION) {
			fileChooser.setCurrentDirectory(new File("/Users/Will/Apps and Tools/Android/workspace/ScrollApp/src/com/productivity/util/resource"));
			fileChooser.showOpenDialog(frame);
			
			FileInputStream fis;
			ObjectInputStream in;
			AnimationCreator ac = null;
			try {
				fis = new FileInputStream(fileChooser.getSelectedFile().getPath());
				in = new ObjectInputStream(fis);
				ac = (AnimationCreator)in.readObject();
			    in.close();
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			ac.setFileName(fileChooser.getSelectedFile().getName().substring(0,fileChooser.getSelectedFile().getName().length()-5));
			frame.add(ac);
		}
		else
			frame.add(new AnimationCreator());
		frame.setSize(new Dimension(500,500));
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
	
	private ArrayList<Joint[]> keyFrames;
	private int clickedJoint = -1;
	private int currentFrame = 0;
	private Point2D clickPoint;
	private double clickAngle;
	private String fileName = "export";
	
	
	public AnimationCreator() {
		this.addKeyListener(this);
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
		keyFrames = new ArrayList<Joint[]>();
		Joint[] joints = new Joint[10];
		joints[5] = new Joint(null,90,1);		//right foot
		joints[4] = new Joint(null, 90, 1);		//left foot
		Joint[] rkc = {joints[5]};
		joints[3] = new Joint(rkc, 60, 1);		//right knee
		Joint[] lkc = {joints[4]};
		joints[2] = new Joint(lkc, 120, 1);		//left knee
		Joint[] hipc = {joints[2],joints[3]};
		joints[1] = new Joint(hipc, 90, 1);		//hip
		joints[9] = new Joint(null, 90, 0.75);	//right hand
		joints[8] = new Joint(null, 90, 0.75);	//left hand
		Joint[] rec = {joints[9]};
		joints[7] = new Joint(rec, 30, 0.75);	//right elbow
		Joint[] lec = {joints[8]};
		joints[6] = new Joint(lec, 150, 0.75);	//left elbow
		Joint[] corec = {joints[7],joints[6],joints[1]};
		
		joints[0] = new Joint(corec,0,0);
		keyFrames.add(joints);
		
	}
	
	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	
	private Joint[] currFrame() {
		return keyFrames.get(currentFrame);
	}
	public void export() {
		FileWriter fstream = null;
		BufferedWriter out = null;
		try {
			fstream = new FileWriter("src/com/productivity/util/resource/" + fileName+".txt");
			out = new BufferedWriter(fstream);
			StringBuilder str = new StringBuilder();
			str.append("{");
			for(int i = 0; i < keyFrames.size()-1;i++) {
				str.append("{");
				exportJoint(keyFrames.get(i)[0],str);
				str.deleteCharAt(str.length()-1);
				str.deleteCharAt(str.length()-1);
				str.append("},\n");
			}
			str.deleteCharAt(str.length()-1);
			str.deleteCharAt(str.length()-1);
			str.append("};");
			out.write(str.toString());
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		FileOutputStream fos = null;
		ObjectOutputStream os = null;
		try
	    {
	      fos = new FileOutputStream("src/com/productivity/util/resource/" + fileName+".anim");
	      os = new ObjectOutputStream(fos);
	      os.writeObject(this);
	      os.close();
	     }
	     catch(IOException ex)
	     {
	       ex.printStackTrace();
	     }
	}
	public void exportJoint(Joint j, StringBuilder str) throws IOException {
		Joint[] c = j.getChildren();
		if(c==null) return;
		Vertex3D v = j.getPoint().scale(1/50.0f);
		for(int i = 0; i < c.length;i++) {
			Vertex3D cv = c[i].getPoint().scale(1/50.0f);
			str.append(v + ", " + cv + ", ");
			exportJoint(c[i], str);
		}
	}
	
	public void paint (Graphics g) {
		drawJoint(currFrame()[0].getPoint(),currFrame()[0], g);
		g.drawString("Frame " + (currentFrame+1), 0, 20);
	}
	
	public void drawJoint(Vertex3D v, Joint j, Graphics g) {
		j.setPoint(v);
		Joint[] c = j.getChildren();
		if(c!=null) {
			for(int i = 0; i < c.length;i++) {
				Vertex3D cv = new Vertex3D((float)(v.getX()+ Math.cos(c[i].getAngle())*c[i].getLength()*50),(float)(v.getY()+ Math.sin(c[i].getAngle())*c[i].getLength()*50),0);
				g.drawLine(250+v.getIntX(), 230+v.getIntY(), 250+cv.getIntX(), 230+cv.getIntY());
				drawJoint(cv,c[i],g);
			}
		}
		if(clickedJoint!=-1 && currFrame()[clickedJoint] == j) {
			g.setColor(Color.YELLOW);
			g.fillOval((int)v.getX()+245, (int)v.getY()+225, 10, 10);
			g.setColor(Color.BLACK);
		}
		else
			g.fillOval((int)v.getX()+245, (int)v.getY()+225, 10, 10);
		g.drawLine(0, 374, 500, 374);
	}
	
	@Override
	public void keyTyped(KeyEvent e) {
		
		
	}

	@Override
	public void keyPressed(KeyEvent e) {
		if(clickedJoint!=-1) {
			if(e.getKeyCode() == KeyEvent.VK_LEFT)
				currFrame()[clickedJoint].setAngle(currFrame()[clickedJoint].getAngleDegrees()+1);
			if(e.getKeyCode() == KeyEvent.VK_RIGHT)
				currFrame()[clickedJoint].setAngle(currFrame()[clickedJoint].getAngleDegrees()-1);
			if(clickedJoint == 0) {
				if(e.getKeyCode() == KeyEvent.VK_UP)
					currFrame()[0].setPoint(new Vertex3D(currFrame()[0].getPoint().getX(),currFrame()[0].getPoint().getY()-1,0));
				if(e.getKeyCode() == KeyEvent.VK_DOWN)
					currFrame()[0].setPoint(new Vertex3D(currFrame()[0].getPoint().getX(),currFrame()[0].getPoint().getY()+1,0));
			}
			repaint();
		}
		
	}

	@Override
	public void keyReleased(KeyEvent e) {
		if(e.getKeyCode()==KeyEvent.VK_E)
			export();
		if(e.getKeyCode()==KeyEvent.VK_I) {
			keyFrames.add(currentFrame+1,Joint.copyJointArray(currFrame()));
			currentFrame++;
		}
		if(e.getKeyCode()==KeyEvent.VK_P) {
			if(currentFrame>0) currentFrame--;
		}
		if(e.getKeyCode()==KeyEvent.VK_N) {
			if(currentFrame<keyFrames.size()-1) currentFrame++;
		}
		if(e.getKeyCode()==KeyEvent.VK_R) {
			if(keyFrames.size()>1) keyFrames.remove(currentFrame);
			if(currentFrame>=keyFrames.size()) currentFrame = keyFrames.size()-1;
		}
		repaint();
	}
	
	

	@Override
	public void mouseClicked(MouseEvent e) {
		
	}

	@Override
	public void mousePressed(MouseEvent e) {
		clickPoint = e.getLocationOnScreen();
		int i;
		for(i = 0; i < currFrame().length;i++)
			if(e.getPoint().distance(currFrame()[i].getPoint().getX()+250, currFrame()[i].getPoint().getY()+230)<12) {
				clickedJoint = i;
				clickAngle = currFrame()[i].getAngleDegrees();
				break;
			}
		if(i==currFrame().length) clickedJoint = -1;	
		repaint();
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void mouseDragged(MouseEvent e) {
		if(clickedJoint!=-1) {
			currFrame()[clickedJoint].setAngle(clickAngle-(e.getLocationOnScreen().getX()-clickPoint.getX()));
			repaint();
		}
	}
	@Override
	public void mouseMoved(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

}

class Joint implements Serializable {
	private Joint[] children;
	private double angle;
	private double length;
	private Vertex3D point;	
	public Joint(Joint[] children, double angle, double length) {
		this.children = children;
		this.angle = angle;
		this.length = length;
		point = new Vertex3D();
	}
	public Joint(Joint j) {
		this.children = copyJointArray(j.getChildren());
		this.angle = j.getAngleDegrees();
		this.length = j.getLength();
		this.point = j.getPoint();
	}
	public static Joint[] copyJointArray(Joint[] arr) {
		if(arr==null) return null;
		Joint[] joints = new Joint[10];
		joints[5] = new Joint(null,arr[5].getAngleDegrees(),arr[5].getLength());		//right foot
		joints[4] = new Joint(null, arr[4].getAngleDegrees(),arr[4].getLength());		//left foot
		Joint[] rkc = {joints[5]};
		joints[3] = new Joint(rkc, arr[3].getAngleDegrees(),arr[3].getLength());		//right knee
		Joint[] lkc = {joints[4]};
		joints[2] = new Joint(lkc, arr[2].getAngleDegrees(),arr[2].getLength());		//left knee
		Joint[] hipc = {joints[2],joints[3]};
		joints[1] = new Joint(hipc, arr[1].getAngleDegrees(),arr[1].getLength());		//hip
		joints[9] = new Joint(null, arr[9].getAngleDegrees(),arr[9].getLength());	//right hand
		joints[8] = new Joint(null, arr[8].getAngleDegrees(),arr[8].getLength());	//left hand
		Joint[] rec = {joints[9]};
		joints[7] = new Joint(rec, arr[7].getAngleDegrees(),arr[7].getLength());	//right elbow
		Joint[] lec = {joints[8]};
		joints[6] = new Joint(lec, arr[6].getAngleDegrees(),arr[6].getLength());	//left elbow
		Joint[] corec = {joints[7],joints[6],joints[1]};
		joints[0] = new Joint(corec,0,0);
		return joints;
	}
	public Vertex3D getPoint() {
		return point;
	}
	public void setPoint(Vertex3D point) {
		this.point = point;
	}
	public Joint[] getChildren() {
		return children;
	}
	public void setChildren(Joint[] children) {
		this.children = children;
	}
	public double getAngle() {
		return (angle*Math.PI)/180;
	}
	public double getAngleDegrees() {
		return angle;
	}
	public void setAngle(double angle) {
		this.angle = angle;
	}
	public double getLength() {
		return length;
	}
	public void setLength(double length) {
		this.length = length;
	}
}
